home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1995 November
/
EnigmA AMIGA RUN 02 (1995)(G.R. Edizioni)(IT)[!][issue 1995-11][Skylink CD].iso
/
earcd
/
util
/
text
/
words3.lha
/
Words
/
WarpSPELL
/
source
/
funcs.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-08-28
|
15KB
|
605 lines
/* -----------------------------------------------------------------------------
WarpSPELL ©1995 Dietmar Eilert
Spell checking syntax parser. Dice:
DMAKE
-------------------------------------------------------------------------------
*/
#include "defs.h"
/// "Header stuff"
// Buffer handles are allocated for each text buffer to keep track of ressources:
struct BufferHandle {
struct EditConfig *bh_EditConfig; // pointer to text data
struct GlobalConfig *bh_GlobalConfig; // editor configuration
struct SyntaxChunk *bh_SyntaxStack; // parser output
struct RefreshRequest bh_RefreshRequest; // display refresh request
UBYTE bh_Command[4096]; // ISpell command buffer
UBYTE bh_Results[4096]; // ISpell result buffer
struct MsgPort *bh_Port; // ISpell reply port
};
#define EMPTY_STACK ((struct SyntaxChunk *)~0) // empty stack flag
///
/// "Prototype"
// library functions
Prototype LibCall struct ParserData *MountScanner(void);
Prototype LibCall ULONG StartScanner(__A0 struct GlobalConfig *, __A1 struct EditConfig *, __D0 struct SyntaxChunk *);
Prototype LibCall ULONG CloseScanner(__D0 ULONG);
Prototype LibCall void FlushScanner(__D0 ULONG);
Prototype LibCall void SetupScanner(__A0 struct GlobalConfig *);
Prototype LibCall struct RefreshRequest *BriefScanner(__D0 ULONG, __A0 struct ScannerNotify *);
Prototype LibCall struct SyntaxChunk *ParseLine (__D0 ULONG, __A0 struct LineNode *, __D1 ULONG);
Prototype LibCall void UnparseLines(__A0 struct LineNode *, __D0 ULONG);
Prototype LibCall void ParseSection(__D0 ULONG, __A0 struct LineNode *, __D1 ULONG);
// private functions
Prototype struct SyntaxChunk *ParseString(UBYTE *, UWORD, ULONG);
Prototype struct SyntaxChunk *DupStack(struct SyntaxChunk *);
Prototype ULONG *SendRexxCommand(UBYTE *, UBYTE *, struct MsgPort *replyPort, UBYTE *);
Prototype BOOL CheckThisWord(ULONG, UBYTE *, UWORD);
Prototype void AlertInfo(UBYTE *);
///
/// "Globals"
BOOL IsLetter[256];
BOOL IsAlNum [256];
///
/// "Library functions"
/* ------------------------------- MountScanner --------------------------------
Called by the editor before first usage of a scanner. Return a description of
our abilities.
*/
__geta4 LibCall struct ParserData *
MountScanner()
{
static UBYTE version[] = "$VER: WarpSPELL 2.0 (" __COMMODORE_DATE__ ")";
static struct ParserData parserData;
UWORD ascii;
// syntax elements understood by parser
static UBYTE *levelNames[] = { "Standard text", "Spelling error", NULL };
static UBYTE *example[] = {
"Aaron ",
"aback ",
"abandon ",
"abase ",
"abash ",
"abate ",
"abatement ",
"abbe ",
"abbess ",
"abbey ",
"abbot ",
"abbreviate ",
"abdicate ",
"abdominal ",
"abduct ",
"adenoids ",
"already ",
"alsatian ",
"also ",
"altar ",
"alter ",
NULL
};
// color suggestions
static ULONG *levelColors[] = {
MAKE_RGB4(0, 0, 0),
MAKE_RGB4(15, 15, 0),
};
parserData.pd_Release = SCANLIBVERSION;
parserData.pd_Version = 1;
parserData.pd_Serial = 0;
parserData.pd_Info = "WarpSPELL 2.0";
parserData.pd_Levels = 2;
parserData.pd_Names = levelNames;
parserData.pd_Colors = levelColors;
parserData.pd_Flags = SCPRF_SYNTAXCACHE;
parserData.pd_Example = example;
// preset globals
for (ascii = 0; ascii < 256; ++ascii)
IsLetter[ascii] = ((ascii >= 'A') && (ascii <= 'Z')) || ((ascii >= 'a') && (ascii <= 'z')) || (ascii >= 'À');
for (ascii = 0; ascii < 256; ++ascii)
IsAlNum[ascii] = ((ascii >= '0') && (ascii <= '9')) || IsLetter[ascii];
return(&parserData);
}
/* ------------------------------- StartScanner --------------------------------
Called by the editor after a new text buffer has been created. We allocate a
buffer to hold text-specific data. The buffer address is returned as handle.
*/
LibCall ULONG
StartScanner(__A0 struct GlobalConfig *globalConfigPtr, __A1 struct EditConfig *editConfigPtr, __D0 struct SyntaxChunk *syntaxStack)
{
struct BufferHandle *handle;
if (handle = AllocVec(sizeof(struct BufferHandle), MEMF_PUBLIC | MEMF_CLEAR)) {
if (handle->bh_Port = CreateMsgPort()) {
handle->bh_GlobalConfig = globalConfigPtr;
handle->bh_EditConfig = editConfigPtr;
handle->bh_SyntaxStack = syntaxStack;
return((ULONG)handle);
}
else
FreeVec(handle);
}
return(NULL);
}
/* ------------------------------- CloseScanner --------------------------------
Called by the editor if a text buffer is about to be closed. Deallocate buffer
specific 'global' data.
*/
LibCall ULONG
CloseScanner(__D0 ULONG scanID)
{
if (scanID) {
struct BufferHandle *handle = (struct BufferHandle *)scanID;
if (handle->bh_Port)
DeleteMsgPort(handle->bh_Port);
FreeVec(handle);
}
return(0);
}
/* ------------------------------- FlushScanner --------------------------------
Called by the editor in low memory situations: we are supposed to free as much
memory as possible.
*/
LibCall void
FlushScanner(__D0 ULONG scanID)
{
struct BufferHandle *handle;
struct EditConfig *config;
struct LineNode *lineNode;
handle = (struct BufferHandle *)scanID;
config = handle->bh_EditConfig;
if (lineNode = config->TextNodes)
UnparseLines(lineNode, config->Lines);
}
/* ------------------------------- SetupScanner --------------------------------
Called by the editor if the user wants to change the scanner's configuration.
We do not support user configuration (parserData.pd_Flags: SCPRF_CONFIGWIN flag
unset).
*/
LibCall void
SetupScanner(__A0 globalConfigPtr)
{
;
}
/* ------------------------------- BriefScanner --------------------------------
Called to notify a context scanner if lines have been added, deleted or
modified. We aren't a context scanner (parserData.pd_Flags: SCPRF_CONTEXT
flag unset), so we won't ever have to request additional display requests:
the editor's built-in refresh of damage regions is sufficient.
*/
LibCall struct RefreshRequest *
BriefScanner(__D0 ULONG scanID, __A0 struct ScannerNotify *notify)
{
return(NULL);
}
/* --------------------------------- ParseLine ---------------------------------
Parse a line, build a syntax description
*/
LibCall struct SyntaxChunk *
ParseLine(__D0 ULONG scanID, __A0 struct LineNode *lineNode, __D1 ULONG line)
{
if (lineNode->Fold)
return(NULL);
else if (lineNode->Len) {
// line not yet parsed ?
if (lineNode->UserData == NULL) {
struct SyntaxChunk *syntaxStack = ParseString(lineNode->Text, lineNode->Len, scanID);
if (syntaxStack == EMPTY_STACK)
lineNode->UserData = EMPTY_STACK;
else
lineNode->UserData = DupStack(syntaxStack);
}
if (lineNode->UserData == EMPTY_STACK)
return((struct SyntaxChunk *)NULL);
else
return((struct SyntaxChunk *)lineNode->UserData);
}
else
return(NULL);
}
/* -------------------------------- UnparseLines -------------------------------
Called by the editor if lines are to be deleted. We are supposed to free
private data attached to the lines.
*/
LibCall void
UnparseLines(__A0 struct LineNode *lineNode, __D0 ULONG lines)
{
while (lines--) {
// free syntax cache
if (lineNode->UserData) {
if (lineNode->UserData != (APTR)EMPTY_STACK)
FreeVec((APTR)lineNode->UserData);
lineNode->UserData = NULL;
}
// free folded subblock
if (lineNode->Fold)
UnparseLines(lineNode->Fold->TextNodes, lineNode->Fold->Lines);
++lineNode;
}
}
/* -------------------------------- ParseSection -------------------------------
Called by the editor if lines are to be displayed. The scanner is encouraged to
preparse the lines.
*/
LibCall void
ParseSection(__D0 ULONG scanID, __A0 struct LineNode *lineNode, __D1 ULONG lines)
{
while (lines--) {
// fold headers have to be ignored
if (lineNode->Fold == NULL) {
// line not yet parsed ?
if (lineNode->Len)
if (lineNode->UserData == NULL)
lineNode->UserData = DupStack(ParseString(lineNode->Text, lineNode->Len, scanID));
}
++lineNode;
}
}
///
/// "private"
/* -------------------------------- ParseString --------------------------------
Parse a string, build a syntax description. This is a simple example only:
C++-Comments (// ....) are highlighted. Return EMPTY_STACK in case there is
nothing to highlight.
*/
struct SyntaxChunk *
ParseString(UBYTE *text, UWORD len, ULONG scanID)
{
if (len) {
struct SyntaxChunk *syntaxStack = ((struct BufferHandle *)scanID)->bh_SyntaxStack;
UWORD indent, elements, wordLen;
elements = 0;
// leading spaces have to be ignored
for (indent = 0; len && (*text == 32); ++indent, --len)
++text;
// trailing spaces have to be ignored
while (len && (text[len - 1] == 32))
--len;
// check every word of this line
while (len) {
// ignore spaces
while (len && (IsLetter[*text] == FALSE)) {
++text;
++indent;
--len;
}
if (len) {
// get next word
wordLen = 1;
while (IsAlNum[text[wordLen]] && (wordLen < len))
++wordLen;
// check word
if (CheckThisWord(scanID, text, wordLen)) {
// highlight word
syntaxStack[elements].sc_Start = indent;
syntaxStack[elements].sc_End = indent + (wordLen - 1);
syntaxStack[elements].sc_Level = 1;
++elements;
}
// move to next word
text += wordLen;
indent += wordLen;
len -= wordLen;
}
}
if (elements) {
// terminate syntax stack
syntaxStack[elements].sc_Start = FALSE;
syntaxStack[elements].sc_End = FALSE;
syntaxStack[elements].sc_Level = FALSE;
return(syntaxStack);
}
}
return(EMPTY_STACK);
}
/* --------------------------------- DupStack ----------------------------------
Duplicate syntax stack (to be FreeVec'ed). Return NULL in case of failure.
*/
struct SyntaxChunk *
DupStack(syntaxStack)
struct SyntaxChunk *syntaxStack;
{
if (syntaxStack && (syntaxStack != EMPTY_STACK)) {
struct SyntaxChunk *chunk;
UWORD elements;
// determine stack size
for (elements = 0, chunk = syntaxStack; chunk->sc_Level; ++chunk)
++elements;
// create copy of syntax stack (to be attached to a text line by the caller)
if (elements) {
ULONG size = (++elements) * sizeof(struct SyntaxChunk);
chunk = syntaxStack;
if (syntaxStack = AllocVec(size, MEMF_PUBLIC))
movmem(chunk, syntaxStack, size);
}
else
syntaxStack = EMPTY_STACK;
}
return(syntaxStack);
}
/* ------------------------------- CheckThisWord -------------------------------
Check word <check> of length <len>. Return TRUE if word is not known. Ignore
single letters.
*/
__geta4 BOOL
CheckThisWord(scanID, check, len)
UBYTE *check;
UWORD len;
ULONG scanID;
{
if (len > 1) {
struct BufferHandle *handle = (struct BufferHandle *)scanID;
UBYTE *command = handle->bh_Command;
strcpy(command, "QUICKCHECK ");
movmem(check, command + 11, len);
command[len + 11] = 0;
// make ISpell check command
if (SendRexxCommand("IRexxSpell", command, handle->bh_Port, handle->bh_Results)) {
if (stricmp(handle->bh_Results, "ok"))
return(TRUE);
else
return(FALSE);
}
}
else
return(FALSE);
}
/* ---------------------------------- SendRexxCommand -------------------------
Send ARexx message & wait for answer. Return pointer to result or NULL.
*/
__geta4 ULONG *
SendRexxCommand(port, cmd, replyPort, buffer)
struct MsgPort *replyPort;
UBYTE *cmd, *port, *buffer;
{
struct MsgPort *rexxport;
Forbid();
if (rexxport = FindPort(port)) {
struct RexxMsg *rexxMsg, *answer;
if (rexxMsg = CreateRexxMsg(replyPort, NULL, NULL)) {
if (rexxMsg->rm_Args[0] = CreateArgstring(cmd, strlen(cmd))) {
static ULONG result;
rexxMsg->rm_Action = RXCOMM | RXFF_RESULT;
PutMsg(rexxport, &rexxMsg->rm_Node);
do {
WaitPort(replyPort);
if (answer = (struct RexxMsg *)GetMsg(replyPort))
result = answer->rm_Result1;
} while (!answer);
Permit();
if (answer->rm_Result1 == RC_OK) {
if (answer->rm_Result2) {
if (buffer)
strcpy(buffer, (char *)answer->rm_Result2);
DeleteArgstring((char *)answer->rm_Result2);
}
}
DeleteArgstring((char *)ARG0(answer));
DeleteRexxMsg(answer);
return(&result);
}
}
}
Permit();
return(NULL);
}
/* --------------------------------- AlertInfo -----------------------------------
Show alert. Returns TRUE if user pressed left button.
*/
__geta4 void
AlertInfo(text)
UBYTE *text;
{
UBYTE *buffer;
if (buffer = AllocVec(80, MEMF_PUBLIC | MEMF_CLEAR)) {
buffer[1] = '\30';
buffer[2] = '\25';
strcpy(buffer + 3, text);
DisplayAlert(RECOVERY_ALERT, buffer, 40);
FreeVec(buffer);
}
}
///